package com.gupao.controller;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.redisson.Redisson;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.common.util.concurrent.RateLimiter;
import com.gupao.jwt.JwtTokenUtils;
import com.gupao.jwt.PassToken;
import com.gupao.model.User;
import com.gupao.redis.RedisCacheManager;
import com.gupao.redis.RedissionManager;
import com.gupao.service.UserService;

@Controller
public class UserController extends BaseController {
	
	@Autowired
	RedisCacheManager redisCacheManager;
	
	@Autowired
	RedissionManager redissionManager;
	
	@Autowired
	RedissonClient redissonClient;
	
	@Autowired
	UserService userService;
	//令牌桶算法                                                                              1：每秒新增的令牌数
	RateLimiter tokenLimiter=RateLimiter.create(1);
	
	//漏桶算法                                                                                 1：每秒新增的令牌数 500：从冷启动速率到平均速率的间隔时间，也可以叫作预热时间                                   
	RateLimiter leakyLimiter=RateLimiter.create(1, 500, TimeUnit.MILLISECONDS);
	
	
	
	
	/**
	 * 令牌桶限流方案一：获取不到令牌，直接走降级
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/tokenBucket")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String tokenBucket() throws Exception {
		long start=System.currentTimeMillis();
		try {
//		    double limiter=rateLimiter.acquire();
//		    System.out.println("获取token时间："+limiter);
//			boolean flag=rateLimiter.tryAcquire();
			//如果500毫秒内获取不到令牌，直接走降级
			boolean flag=tokenLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
			if(!flag) {
				System.out.println("服务器太忙了！");
				return "服务器太忙了！";
			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功："+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时："+(end-start));
		}
	}
	
	/**
	 * 令牌桶限流方案二：如果获取不到令牌，就一直等待
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/tokenBucket1")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String tokenBucket1() throws Exception {
		long start=System.currentTimeMillis();
		try {
			//如果获取不到令牌 就一直等待
		    double limiter=tokenLimiter.acquire();
		    System.out.println("获取token时间："+limiter);
//			boolean flag=rateLimiter.tryAcquire();
//			if(!flag) {
//				System.out.println("服务器太忙了！");
//				return "服务器太忙了！";
//			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功："+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时："+(end-start));
		}
	}
	
	/**
	 * 漏桶限流方案一：如果获取不到令牌，直接走降级
	 * @return
	 */
	@RequestMapping("/leakyBucket1")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String leakyBucket1() {
		long start=System.currentTimeMillis();
		try {
//		    double limiter=rateLimiter.acquire();
//		    System.out.println("获取token时间："+limiter);
//			boolean flag=rateLimiter.tryAcquire();
			boolean flag=leakyLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
			if(!flag) {
				System.out.println("服务器太忙了！");
				return "服务器太忙了！";
			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功："+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时："+(end-start));
		}
	}
	
	/**
	 * 漏桶限流方案二：如果获取不到令牌，就一直等待
	 * @return
	 */
	@RequestMapping("/leakyBucket")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String leakyBucket() {
		long start=System.currentTimeMillis();
		try {
		    double limiter=leakyLimiter.acquire();
		    System.out.println("获取token时间："+limiter);
//			boolean flag=rateLimiter.tryAcquire();
//			if(!flag) {
//				System.out.println("服务器太忙了！");
//				return "服务器太忙了！";
//			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功："+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时："+(end-start));
		}
	}
	
	/**
	 * 分布式限流方案二：如果获取不到令牌，就一直等待
	 * @return
	 */
	@RequestMapping("/redissionLimit")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String redissionLimit() {
		long start=System.currentTimeMillis();
		try {
			RRateLimiter redisLimiter=redissionManager.getRRateLimiter("userLimiter");
			redisLimiter.trySetRate(RateType.PER_CLIENT, 1, 1, RateIntervalUnit.SECONDS);
			redisLimiter.acquire();
//			System.out.println("获取token时间："+limiter);
			
//			boolean flag=rateLimiter.tryAcquire();
//			if(!flag) {
//				System.out.println("服务器太忙了！");
//				return "服务器太忙了！";
//			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功："+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时："+(end-start));
		}
	}
	
	/**
	 * 分布式限流方案一：如果获取不到令牌，直接走降级
	 * @return
	 */
	@RequestMapping("/redissionLimit1")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String redissionLimit1() {
		long start=System.currentTimeMillis();
		try {
//			Config config = new Config();
//			config.useSingleServer().setAddress("redis://192.168.126.11:6379");
//			RedissonClient redissionLimiter = Redisson.create(config);
//			RRateLimiter redisLimiter=redissionLimiter.getRateLimiter("test");
//			redisLimiter.trySetRate(RateType.PER_CLIENT, 1, 1, RateIntervalUnit.SECONDS);
			RRateLimiter redisLimiter=redissionManager.getRRateLimiter("userLimiter");
			redisLimiter.trySetRate(RateType.PER_CLIENT, 1, 1, RateIntervalUnit.SECONDS);
			boolean flag=redisLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
			if(!flag) {
				System.out.println("服务器太忙了！");
				return "服务器太忙了！";
			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功："+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时："+(end-start));
		}
	}

	@RequestMapping("/login")
	@ResponseBody
//	@UserLoginToken
//	@PassToken
	public String login(@Param("name") String name, @Param("password") String password) {
		User user = userService.login(name, password);
		if (user == null) {
			return "login fail";
		} else {
			return "success:" + JwtTokenUtils.getToken(user);
		}
	}

	@RequestMapping("/getUid")
	@ResponseBody
//	@UserLoginToken
	public String getUid() {
		return super.getUid();
	}
	
	
}
